/*
 * Copyright (c) 2010 Curtis Boyden.  All rights reserved. 
 * This software was developed by Curtis Boyden and is provided under the terms 
 * of the GNU Lesser General Public License, Version 2.1. You may not use 
 * this file except in compliance with the license. If you need a copy of the license, 
 * please go to http://www.gnu.org/licenses/lgpl-2.1.txt. The Original Code is ejMud
 * (Ewerp Java MUD).  The Initial Developer is Curtis Boyden.
 *
 * Software distributed under the GNU Lesser Public License is distributed on an "AS IS" 
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or  implied. Please refer to 
 * the license for the specific language governing your rights and limitations.
*/

package com.ewerp.mud.commands.create;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

import com.ewerp.mud.commands.BaseCommand;
import com.ewerp.mud.commands.ICommand;
import com.ewerp.mud.core.persistence.IPersistenceManager;
import com.ewerp.mud.core.persistence.IPersistenceSession;
import com.ewerp.mud.core.session.parsers.TerminalLineParser.ITerminalLinePacketParser;
import com.ewerp.mud.entities.IEntity;
import com.ewerp.mud.entities.ObjectId;

public class SetPropertyCommand extends BaseCommand {
    public static class SetPropertyTerminalLinePacketParser implements ITerminalLinePacketParser {
        @Override
        public ICommand parseTerminalLinePacket(IEntity source, String input) {

            String[] tokens = input.split(" ");

            if (tokens.length > 1) {
                SetPropertyCommand cmd = new SetPropertyCommand();
                cmd.setSource(source);
                cmd.setItemId(tokens[1]);
                cmd.setPropertyName(tokens[2]);
                cmd.setPropertyValue(tokens[3]);
                return cmd;
            }
            return null;
        }
    }

    protected IEntity source;
    protected String itemId;
    protected String propertyName;
    protected Object propertyValue;

    @Override
    public void execute() throws IllegalStateException {
        IPersistenceSession persistence = ((IPersistenceManager)getPluginManager().getPlugin(IPersistenceManager.class)).openSession();
        IEntity entity = persistence.fetch(new ObjectId(getItemId()));
        
        // Search for the requested property
        String methodName = "set" + getPropertyName();
        
        try {
            Method setter = null;
            try {
                setter = entity.getClass().getMethod(methodName, getPropertyValue().getClass());
            } catch (NoSuchMethodException e) {
                // Search for a setter
                Method[] methods = entity.getClass().getMethods();
                List<Method> setters = new ArrayList<Method>();
                if(methods != null) {
                    for(int i = 0; i < methods.length; i++) {
                        if(methods[i].getName().equalsIgnoreCase(methodName)) {
                            setters.add(methods[i]);
                        }
                    }
                }
                
                // Search matching methods for the best parameter match
                if(setters.size() > 0) {
                    for(Method m : setters) {
                        Class<?>[] parameters = m.getParameterTypes();
                        if(parameters != null && parameters.length == 1) {
                            // We have a potential setter
                            if(IEntity.class.isAssignableFrom(parameters[0])) {
                                // We have a valid setter of another IEntity object. The incoming value should Hex String or the
                                setter = m;
                                IEntity propertyEntity = null;
                                Object value = getPropertyValue();
                                
                                if(value instanceof String) {
                                    propertyEntity = persistence.fetch(new ObjectId((String)value));
                                } else if((value instanceof Long) ||
                                        (value instanceof Integer)) {
                                    propertyEntity = persistence.fetch(new ObjectId((Long)value));
                                }
                                
                                setPropertyValue(propertyEntity);
                                break;
                            }
                        }
                    }
                }
            }
            setter.invoke(entity, getPropertyValue());
        } catch (SecurityException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        
        persistence.commit();
        
        System.out.println(entity);
    }
    
    public IEntity getSource() {
        return source;
    }

    public void setSource(IEntity source) {
        this.source = source;
    }

    public String getItemId() {
        return itemId;
    }

    public void setItemId(String itemId) {
        this.itemId = itemId;
    }

    public String getPropertyName() {
        return propertyName;
    }

    public void setPropertyName(String propertyName) {
        this.propertyName = propertyName;
    }

    public Object getPropertyValue() {
        return propertyValue;
    }

    public void setPropertyValue(Object propertyValue) {
        this.propertyValue = propertyValue;
    }

}
